/*
 * Copyright 2005-2013 finalist.cn. All rights reserved.
 * Support: http://www.finalist.cn
 * License: http://www.finalist.cn/license
 */
package com.finalist.plugin.unionpay;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.finalist.Setting;
import com.finalist.entity.Payment;
import com.finalist.plugin.PaymentPlugin;
import com.finalist.util.SettingUtils;

/**
 * Plugin - 银联在线支付
 * 
 * @author Finalist IT Group
 * @version 3.0
 */
@Component("unionpayPlugin")
public class UnionpayPlugin extends PaymentPlugin {
	
	private static Logger log  = Logger.getLogger(UnionpayPlugin.class);
	//private static final String MER_ID = "104110553990004";//乐语电信
//	private static final String SECURE_KEY = "SDF73EFJ9D8SFKJ3F7YSDIJFAOJDF8HS";//乐语电信
	
	private static final String MER_ID = "104110553990001";//乐语商贸
	private static final String SECURE_KEY = "DFWE7GFYSDJIG783EGJOS90AGKJGKJ";//乐语商贸
	/** 货币 */
	private static final String CURRENCY = "156";

	@Override
	public String getName() {
		return "银联在线支付";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public String getAuthor() {
		return "finalist";
	}

	@Override
	public String getSiteUrl() {
		return "http://www.finalist.cn";
	}

	@Override
	public String getInstallUrl() {
		return "unionpay/install.jhtml";
	}

	@Override
	public String getUninstallUrl() {
		return "unionpay/uninstall.jhtml";
	}

	@Override
	public String getSettingUrl() {
		return "unionpay/setting.jhtml";
	}

	@Override
	public String getRequestUrl() {
		return "https://unionpaysecure.com/api/Pay.action";
	}

	@Override
	public RequestMethod getRequestMethod() {
		return RequestMethod.post;
	}

	@Override
	public String getRequestCharset() {
		return "UTF-8";
	}

	@Override
	public Map<String, Object> getParameterMap(String sn, String description, HttpServletRequest request) {
		Setting setting = SettingUtils.get();
		Payment payment = getPayment(sn);
		Map<String, Object> parameterMap = new HashMap<String, Object>();
		parameterMap.put("version", "1.0.0");
		parameterMap.put("charset", "UTF-8");
		parameterMap.put("transType", "01");
		parameterMap.put("origQid", "");
		parameterMap.put("merId", MER_ID);
		parameterMap.put("merAbbr", "乐语商城");
		parameterMap.put("acqCode", "");
		parameterMap.put("merCode", "");
		parameterMap.put("commodityUrl", setting.getSiteUrl());
		parameterMap.put("commodityName", StringUtils.abbreviate(description.replaceAll("[^0-9a-zA-Z\\u4e00-\\u9fa5 ]", ""), 200));
		parameterMap.put("commodityUnitPrice", "");
		parameterMap.put("commodityQuantity", "");
		parameterMap.put("commodityDiscount", "");
		parameterMap.put("transferFee", "");
		parameterMap.put("orderNumber", sn);
		parameterMap.put("orderAmount", payment.getAmount().multiply(new BigDecimal(100)).setScale(0).toString());
		parameterMap.put("orderCurrency", CURRENCY);
		parameterMap.put("orderTime", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
		parameterMap.put("customerIp", request.getLocalAddr());
		parameterMap.put("customerName", "");
		parameterMap.put("defaultPayType", "");
		parameterMap.put("defaultBankNumber", "");
		parameterMap.put("transTimeout", getTimeout() * 60000);
		parameterMap.put("frontEndUrl", getNotifyUrl(sn, NotifyMethod.sync));
		parameterMap.put("backEndUrl", getNotifyUrl(sn, NotifyMethod.async));
		parameterMap.put("merReserved", "");
		parameterMap.put("signMethod", "MD5");
		parameterMap.put("signature", generateSign(parameterMap));
		return parameterMap;
	}

	@Override
	public boolean verifyNotify(String sn, NotifyMethod notifyMethod, HttpServletRequest request) {
		Payment payment = getPayment(sn);
		
		Map<String, Object> parameterMap = new LinkedHashMap<String, Object>();
		parameterMap.put("charset", request.getParameter("charset"));
		parameterMap.put("cupReserved", request.getParameter("cupReserved"));
		parameterMap.put("exchangeDate", request.getParameter("exchangeDate"));
		parameterMap.put("exchangeRate", request.getParameter("exchangeRate"));
		parameterMap.put("merAbbr", request.getParameter("merAbbr"));
		parameterMap.put("merId", request.getParameter("merId"));
		parameterMap.put("orderAmount", request.getParameter("orderAmount"));
		parameterMap.put("orderCurrency", request.getParameter("orderCurrency"));
		parameterMap.put("orderNumber", request.getParameter("orderNumber"));
		parameterMap.put("qid", request.getParameter("qid"));
		parameterMap.put("respCode", request.getParameter("respCode"));
		parameterMap.put("respMsg", request.getParameter("respMsg"));
		parameterMap.put("respTime", request.getParameter("respTime"));
		parameterMap.put("settleAmount", request.getParameter("settleAmount"));
		parameterMap.put("settleCurrency", request.getParameter("settleCurrency"));
		parameterMap.put("settleDate", request.getParameter("settleDate"));
		parameterMap.put("traceNumber", request.getParameter("traceNumber"));
		parameterMap.put("traceTime", request.getParameter("traceTime"));
		parameterMap.put("transType", request.getParameter("transType"));
		parameterMap.put("version", request.getParameter("version"));
		
		if (generateSign(parameterMap).equals(request.getParameter("signature"))) {
			log.info("unipay check sign success");
			if(MER_ID.equals(request.getParameter("merId")) && sn.equals(request.getParameter("orderNumber")) && CURRENCY.equals(request.getParameter("orderCurrency")) && "00".equals(request.getParameter("respCode"))
				&& payment.getAmount().multiply(new BigDecimal(100)).compareTo(new BigDecimal(request.getParameter("orderAmount"))) == 0) {
				return true;
			}
		}
		return false;
	}

	@Override
	public String getNotifyMessage(String sn, NotifyMethod notifyMethod, HttpServletRequest request) {
		if (notifyMethod == NotifyMethod.async) {
			return "";
		}
		return null;
	}

	@Override
	public Integer getTimeout() {
		return 21600;
	}

	/**
	 * 生成签名
	 * 
	 * @param parameterMap
	 *            参数
	 * @return 签名
	 */
	private String generateSign(Map<String, ?> parameterMap) {
		String key = "&" + DigestUtils.md5Hex(SECURE_KEY);
		String src = joinKeyValue(new TreeMap<String, Object>(parameterMap), null, key, "&", false, "signMethod", "signature");
		log.info("md5 source=======" + src);
		log.info("md5 result=======" + DigestUtils.md5Hex(src));
		return DigestUtils.md5Hex(src);
	}
}